package nl.unimaas.micc.eventSnookerTest.domain;

import nl.unimaas.micc.eventSnookerTest.domain.Ball.BallState;
import nl.unimaas.micc.eventSnookerTest.math.BairstowSolver;
import nl.unimaas.micc.eventSnookerTest.math.Transformation3D;
import nl.unimaas.micc.eventSnookerTest.math.Vector3D;
import nl.unimaas.micc.eventSnookerTest.math.XYRotationTrans3D;
import nl.unimaas.micc.eventSnookerTest.simulation.physics.Physics;

public class Cushion {
	
	public enum Orientations{
		NORTH,
		EAST,
		SOUTH,
		WEST;
	}
	
	private Orientations orientation;
	private double xValue, yValue;
	private static BairstowSolver bs = new BairstowSolver(null,2);

	
	public Cushion(double xValue, double yValue, Orientations orientation){
		this.xValue = xValue;
		this.yValue = yValue;
		this.orientation = orientation;
	}
	
	public double getCollisionTime(BilliardBall ball){
		double r = ball.getRadius();
		Vector3D position = ball.getPosition();
		double posX = position.x;
		double posY = position.y;
		double coeff0x = 0;
		double coeff0y = 0;
		
		if(orientation == Orientations.NORTH){
			coeff0x = 0;
			coeff0y = -(yValue - r);
		}
		if(orientation == Orientations.EAST){
			coeff0x = -(xValue - r);
			coeff0y = 0;
		}
		if(orientation == Orientations.SOUTH){
			coeff0x = 0;
			coeff0y = -(yValue + r);
		}
		if(orientation == Orientations.WEST){
			coeff0x = -(xValue + r);
			coeff0y = 0;
		}
		
		coeff0x += posX;
		coeff0y += posY;
		
		
		if(ball.getState() == BallState.SLIDING){
			
			//System.out.println("Ball is SLIDING");
			double ang = -ball.getVelocity().angleTo(new Vector3D(1, 0, 0));	
			Transformation3D tableToBall = new XYRotationTrans3D(ang);
			
			Vector3D u = Physics.getRelativeVelocity(ball, tableToBall).unit();
						
			double mu = ball.getState().getMotion().getFriction(ball);
			double g = Physics.g;
			double ux = u.x;
			double uy = u.y;
			
			double v0 = ball.getVelocity().getLength();
			
			
			double coeff1x = Math.cos(ang) * v0;
			double coeff1y = Math.sin(ang) * v0;
			
			double coeff2part1 = 0.5 * mu * g;
			
			double coeff2x = coeff2part1 * (Math.cos(ang)*ux - Math.sin(ang)*uy);
			double coeff2y = coeff2part1 * (Math.sin(ang)*ux + Math.cos(ang)*uy);
			
			double[] coeffx = new double[]{coeff0x,coeff1x,-coeff2x};
			double[] coeffy = new double[]{coeff0y,coeff1y,-coeff2y};
			
			double solution1 = 0;
			double solution2 = 0;
			
			bs.setCoefficients(coeffx);
			bs.solve();
			try{
				solution1 = bs.getMinReal();
			}
			catch(Exception e){
			}
			bs.setCoefficients(coeffy);
			bs.solve();
			try{
				solution2 = bs.getMinReal();
			}
			catch(Exception e){
				
			}
			if(orientation == Orientations.NORTH || orientation == Orientations.SOUTH){
				return solution2;
			}
			else return solution1;
		}
		
		if (ball.getState() == BallState.ROLLING){
			
			//System.out.println("Ball is ROLLING");
			double mu = ball.getState().getMotion().getFriction(ball);
			double g = Physics.g;

			Vector3D v = ball.getVelocity();
			double vx = v.x;
			double vy = v.y;
			
			Vector3D vUnit = v.unit();
			double vUx = vUnit.x;
			double vUy = vUnit.y;

			double coeff1x = vx;
			double coeff1y = vy;
			
			double coeff2x = vUx * 0.5 * mu * g;
			double coeff2y = vUy * 0.5 * mu * g;
			
			double[] coeffx = new double[]{coeff0x,coeff1x,-coeff2x};
			double[] coeffy = new double[]{coeff0y,coeff1y,-coeff2y};
			
			double solution1 = 0;
			double solution2 = 0;
			bs.setCoefficients(coeffx);
			bs.solve();
			try{
				solution1 = bs.getMinReal();
			}
			catch(Exception e){
			}
			bs.setCoefficients(coeffy);
			bs.solve();
			try{
				solution2 = bs.getMinReal();
			}
			catch(Exception e){
				
			}
			
			
			if(orientation == Orientations.NORTH || orientation == Orientations.SOUTH){
				return solution2;
			}
			else return solution1;		
		}
		return 0;
	}

	
}

